package scalaSciCommands;

import java.util.*;
import java.lang.reflect.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.tree.*;
import scalaExec.Interpreter.GlobalValues;


public class Inspect
{

    
   public static void inspect(Object object)
   {
      
         // print class name and superclass name (if != Object)
         Class cl = null;
         if (object instanceof Class)
             cl = (Class)object;
         else
             cl = object.getClass();
         String name = cl.getName();

         Class supercl = cl.getSuperclass();
         String modifiers = Modifier.toString(cl.getModifiers());
         if (modifiers.length() > 0) System.out.print(modifiers + " ");
         System.out.print("class " + name);
         if (supercl != null && supercl != Object.class) System.out.print(" extends "
               + supercl.getName());

         System.out.print("\n{\n");
         printConstructors(cl);
         System.out.println();
         printMethods(cl);
         System.out.println();
         printFields(cl);
         System.out.println("}");
      }

   /* inspect the variable passed by its identifier, e.g.
    var   myVec= vrand(900)
    inspectg(myVec)
    */
        public static void inspectg(Object object)
   {
      
         // print class name and superclass name (if != Object)
         Class cl = null;
         if (object instanceof Class)
             cl = (Class)object;
         else
             cl = object.getClass();
         String name = cl.getName();
         
         System.out.println("name of class of object = "+name);
         inspectg(name);
        }
        
     
        // inspect the variable type graphically
        // it is required since when we select the variable myVec, we have available the variable as String
     public static void inspectg(String nameOfType)
   {
      
 DefaultMutableTreeNode root = new DefaultMutableTreeNode("Contents of class " +nameOfType);
   
         Class cl=null;
         Class supercl = null;
         String modifiers = "";
        try {
         cl = Class.forName(nameOfType, false, GlobalValues.extensionClassLoader);
         supercl = cl.getSuperclass();
         modifiers = Modifier.toString(cl.getModifiers());
    } catch (ClassNotFoundException ex) {
            Logger.getLogger(Inspect.class.getName()).log(Level.SEVERE, null, ex);
        }
        
                   
         String extendsClass = " ";
         if (supercl != null ) 
             extendsClass +=  " extends " + supercl.getName();
 DefaultMutableTreeNode clDescr = new DefaultMutableTreeNode(modifiers + "  class "+nameOfType+" extends "+extendsClass);
         root.add(clDescr);
        
  DefaultMutableTreeNode nConstructors  = new DefaultMutableTreeNode("Constructors");
  DefaultMutableTreeNode nMethods  = new DefaultMutableTreeNode("Methods");
  DefaultMutableTreeNode nFields  = new DefaultMutableTreeNode("Fields");

  java.lang.reflect.Constructor [] classConstructors = cl.getConstructors();
 for (int k=0; k<classConstructors.length; k++) {
      Constructor  currentConstructor = classConstructors[k];
       DefaultMutableTreeNode  constructorNode = new DefaultMutableTreeNode(classConstructors[k].toString());
       nConstructors.add(constructorNode);
     }
     
    java.lang.reflect.Method []  classMethods = cl.getMethods();
for (int k=0; k<classMethods.length; k++) {
      Method currentMethod = classMethods[k];
      int  methodModifier = currentMethod.getModifiers();
      if (Modifier.isPublic(methodModifier) || Modifier.isStatic(methodModifier)) {
          DefaultMutableTreeNode  methodNode = new DefaultMutableTreeNode(classMethods[k].toString());
          nMethods.add(methodNode);
     }
   }

    java.lang.reflect.Field [] classFields  = cl.getDeclaredFields();
    for (int k=0; k<classFields.length; k++) {
      Field  current = classFields[k];
      DefaultMutableTreeNode  fieldNode = new DefaultMutableTreeNode(current.toString());
      nFields.add(fieldNode);
     }

   root.add(nConstructors);
   root.add(nMethods);
   root.add(nFields);

    JTree  inspectTree = new JTree(root);
    JFrame inspectFrame = new JFrame("Inspect Variable");
    inspectFrame.add(inspectTree);
    inspectFrame.setSize(300, 300);
    inspectFrame.setVisible(true);
        
        
   }
        
   /**
    * Prints all constructors of a class
    * @param cl a class
    */
   public static void printConstructors(Class cl)
   {
      Constructor[] constructors = cl.getDeclaredConstructors();

      for (Constructor c : constructors)
      {
         String name = c.getName();
         System.out.print("   ");
         String modifiers = Modifier.toString(c.getModifiers());
         if (modifiers.length() > 0) System.out.print(modifiers + " ");         
         System.out.print(name + "(");

         // print parameter types
         Class[] paramTypes = c.getParameterTypes();
         for (int j = 0; j < paramTypes.length; j++)
         {
            if (j > 0) System.out.print(", ");
            System.out.print(paramTypes[j].getName());
         }
         System.out.println(");");
      }
   }

   /**
    * Prints all methods of a class
    * @param cl a class
    */
   public static void printMethods(Class cl)
   {
      Method[] methods = cl.getDeclaredMethods();

      for (Method m : methods)
      {
         Class retType = m.getReturnType();
         String name = m.getName();

         System.out.print("   ");
         // print modifiers, return type and method name
         String modifiers = Modifier.toString(m.getModifiers());
         if (modifiers.length() > 0) System.out.print(modifiers + " ");         
         System.out.print(retType.getName() + " " + name + "(");

         // print parameter types
         Class[] paramTypes = m.getParameterTypes();
         for (int j = 0; j < paramTypes.length; j++)
         {
            if (j > 0) System.out.print(", ");
            System.out.print(paramTypes[j].getName());
         }
         System.out.println(");");
      }
   }

   /**
    * Prints all fields of a class
    * @param cl a class
    */
   public static void printFields(Class cl)
   {
      Field[] fields = cl.getDeclaredFields();

      for (Field f : fields)
      {
         Class type = f.getType();
         String name = f.getName();
         System.out.print("   ");
         String modifiers = Modifier.toString(f.getModifiers());
         if (modifiers.length() > 0) System.out.print(modifiers + " ");         
         System.out.println(type.getName() + " " + name + ";");
      }
   }
}
